﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Box2D.XNA;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
///<Summary>
/// A simple wrapper over Box2D body
///</Summary>

namespace Imagine
{
    
    public enum eShapeType
    {
        Shape_Box,
        Shape_Circle,
        Shape_Edge,
        Shape_Polygon
    }

    public class PhysicsSprite : AnimatedSprite
    {
        public PhysicsSprite(string texture) : base(texture) 
        {
            m_physBody = null;
            m_bodyType = BodyType.Static;       //By default make Static,since thats Box2D's default
            m_density = 0.0f;       
            m_friction = 0.0f;
            m_isSensor = false;
            m_groupIndex = 0;
            m_fixedRotation = false;
            m_bullet = false;
            //By default the collsion Body will be the same as Source Reactangle
            m_collisionBody = new Vector2(m_sourceRectangle.Width, m_sourceRectangle.Height);
        }

        #region Properties
        public BodyType BodyType
        {
            get { return m_bodyType;    }
            set { m_bodyType = value;   }
        }

        public Body Body
        {
            get { return m_physBody;    }
            set { m_physBody = value;   }
        }

        //By default it will be the same as Source Recatngle's width/height, but if you want a different dimension change it manually
        //But you better know what you are doing
        //Basically its just Collision Dimensions
        public Vector2 CollisionBody    
        {
            get { return m_collisionBody;   }
            set {m_collisionBody = value;   }
        }

        public float Density
        {
            get {return m_density;      }
            set { m_density = value;    }
        }

        public float Friction
        {
            get { return m_friction;    }
            set { m_friction = value;   }
        }

        public float Restitution
        {
            get { return m_restitution; }
            set { m_restitution = value;}
        }

        public bool IsSensor
        {
            get { return m_isSensor;    }
            set { m_isSensor = value;   }
        }

        public bool FixedRotation
        {
            get { return m_fixedRotation;   }
            set { m_fixedRotation = value;  }
        }

        public short GroupIndex
        {
            get { return m_groupIndex;  }
            set { m_groupIndex = value; }
        }
        public bool Bullet
        {
            set { m_bullet = value; }
        }
        public bool IsBullet
        {
            get { return m_bullet;    }            
        }
        #endregion

        /// <summary>
        /// This function must ABSOLUTELY be called AFTER setting all the properties
        /// This will do the actual initialization and add the body into Box2D's world
        /// After you call the function you are done, you now hand over everything to Box2D
        /// Dont try to change the values manually , that will mess up the simulation
        /// </summary>
        public void InitPhysics(eShapeType type, object userData)
        {
            //Create A fixture
            FixtureDef fxDef = new FixtureDef();
            fxDef.density = m_density;
            fxDef.friction = m_friction;
            fxDef.isSensor = m_isSensor;
            fxDef.filter.groupIndex = m_groupIndex;
            fxDef.restitution = m_restitution;
            fxDef.userData = userData;

            //create a Shape for the Sprite
            PolygonShape pshape;
            CircleShape cshape;

            switch(type)
            {
                case eShapeType.Shape_Box:
                    {
                        pshape = new PolygonShape();
                        //Multiplying by 0.5 is essential as Box2D takes half width and height
                        //PhysicsScale is used to convert b/w Metres and pixels                        
                        pshape.SetAsBox( 0.5f * m_collisionBody.X/Utility.PhysicsScale, 0.5f * m_collisionBody.Y/Utility.PhysicsScale);
                        fxDef.shape = pshape;                        
                        break;
                    }

                case eShapeType.Shape_Circle:
                    {
                        cshape = new CircleShape();
                        cshape._radius = 0.5f * m_collisionBody.X/Utility.PhysicsScale;
                        fxDef.shape = cshape;                        
                        break;
                    }

                //For Now I need only these two
            }

            //Create a BodyDef
            BodyDef def = new BodyDef();
            def.position = m_position/Utility.PhysicsScale;
            def.fixedRotation = m_fixedRotation;
            def.angle = Utility.ToRadians(m_angle);
            def.type = m_bodyType;
            if(m_bullet)
                def.bullet = true;
            
            //Tell the World to create a body 
            m_physBody = TheWorld.Instance().PhysicsWorld.CreateBody(def);
            m_physBody.CreateFixture(fxDef);
            m_physBody.SetUserData(userData);           //Create a cycle, if we have body we get sprite, if we have sprite we get body
        }

        public override bool Update(GameTime time)
        {
            //Update the Animaton
            base.Update(time);   
            //Update the position and Angle
            if(m_physBody != null)
            {
                m_position = m_physBody.GetPosition() * Utility.PhysicsScale;
                m_angle = m_physBody.GetAngle();
            }
            return true;
        }

        public override bool Draw(GameTime time)
        {
          return base.Draw(time);
        }


        #region Private_Parts
        	Body            m_physBody;
            Vector2         m_collisionBody;
            float           m_density;
            float           m_friction;
            float           m_restitution;
            BodyType        m_bodyType;
            bool            m_isSensor;
            bool            m_fixedRotation;
            bool            m_bullet;
            short           m_groupIndex;
        #endregion
    }
}
